package com.mzy.NetworkProgram.networkinterfacebasic.utils;


import com.mzy.NetworkProgram.networkinterfacebasic.data.Constants;
import com.mzy.NetworkProgram.networkinterfacebasic.data.FileSystemInfo;
import com.mzy.NetworkProgram.networkinterfacebasic.data.MemInfo;
import com.mzy.NetworkProgram.networkinterfacebasic.data.PortInfo;
import com.mzy.NetworkProgram.networkinterfacebasic.networkimagess.OshiCollectUtils;
import oshi.software.os.InternetProtocolStats;
import oshi.util.ExecutingCommand;


import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @ClassName
 * @Description
 * @Author dyf
 * @Date 2021/4/21
 * @Version 1.0
 */
public class JavaCollectUtils {

    private JavaCollectUtils() {
        throw new IllegalStateException("Utility class");
    }

    static final OperatingSystemMXBean SYSTEM_MX_BEAN = ManagementFactory.getOperatingSystemMXBean();
    static final String[] WIN_NETSTAT = {"cmd", "/c", "netstat", "-an", "|", "findstr", "LISTENING UDP"};
    static final String[] LINUX_NETSTAT = {"/bin/sh", "-c", "netstat", "-antu", "|", "grep", "-Ei", "LISTEN|udp", "|", "awk", "{print $1\" \"$4\" \"$5}"};

    public static Double getCpuUsage() {
        Double usage = null;
        if (SYSTEM_MX_BEAN instanceof com.sun.management.OperatingSystemMXBean) {
            usage = ((com.sun.management.OperatingSystemMXBean) SYSTEM_MX_BEAN).getSystemCpuLoad() * 100.0D;
        }
        return usage;
    }

    public static Double getMemUsage() {
        Double usage = null;
        if (SYSTEM_MX_BEAN instanceof com.sun.management.OperatingSystemMXBean) {
            long totalvirtualMemory = ((com.sun.management.OperatingSystemMXBean) SYSTEM_MX_BEAN)
                    .getTotalPhysicalMemorySize();
            // 剩余的物理内存
            long freePhysicalMemorySize = ((com.sun.management.OperatingSystemMXBean) SYSTEM_MX_BEAN)
                    .getFreePhysicalMemorySize();
            usage = (1 - freePhysicalMemorySize * 1.0 / totalvirtualMemory) * 100;
        }
        return usage;
    }

    public static Double getFileSystemUsage() {
        File[] disks = File.listRoots();
        long freeSpace = 0;
        long totalSpace = 0;
        for (File file : disks) {
            freeSpace += file.getFreeSpace();
            totalSpace += file.getTotalSpace();
        }
        return totalSpace != 0 ? (1 - freeSpace * 1.0D / totalSpace) * 100 : null;
    }

    public static MemInfo getMemInfo() {
        MemInfo memInfo = new MemInfo();
        if (SYSTEM_MX_BEAN instanceof com.sun.management.OperatingSystemMXBean) {

            long freePhysical = ((com.sun.management.OperatingSystemMXBean) SYSTEM_MX_BEAN).getFreePhysicalMemorySize();
            long freeSwap = ((com.sun.management.OperatingSystemMXBean) SYSTEM_MX_BEAN).getFreeSwapSpaceSize();
            long totalPhysical = ((com.sun.management.OperatingSystemMXBean) SYSTEM_MX_BEAN).getTotalPhysicalMemorySize();
            long totalSwap = ((com.sun.management.OperatingSystemMXBean) SYSTEM_MX_BEAN).getTotalSwapSpaceSize();
            double physicalUsage = (totalPhysical - freePhysical) / (double) totalPhysical;
            double swapUsage = (totalSwap - freeSwap) / (double) totalSwap;

            memInfo.setFreePhysicalMemory(freePhysical);
            memInfo.setFreeSwapSpace(freeSwap);
            memInfo.setTotalPhysicalMemory(totalPhysical);
            memInfo.setTotalSwapSpace(totalSwap);
            memInfo.setPhysicalUsage(physicalUsage);
            memInfo.setSwapUsage(swapUsage);
        }
        return memInfo;
    }

    public static List<FileSystemInfo> getFileSystemInfo() {
        List<FileSystemInfo> fileSystemInfos = new ArrayList<>();
        File[] disks = File.listRoots();
        for (File file : disks) {
            FileSystemInfo fileSystemInfo = new FileSystemInfo();
            fileSystemInfo.setName(file.getAbsolutePath());
            fileSystemInfo.setFreeSpace(file.getFreeSpace());
            fileSystemInfo.setTotalSpace(file.getTotalSpace());
            fileSystemInfo.setUsage((file.getTotalSpace() - file.getFreeSpace()) / (double) file.getTotalSpace());

            fileSystemInfos.add(fileSystemInfo);
        }
        return fileSystemInfos;
    }

    public static List<PortInfo> getPortInfo() {
        String[] cmd = Constants.IS_WIN ? WIN_NETSTAT : LINUX_NETSTAT;
        List<String> lines = ExecutingCommand.runNative(cmd, null);
        List<PortInfo> portInfos = lines.stream().map(line -> {
            String[] a = line.trim().split(" +");
            PortInfo portInfo = new PortInfo();
            portInfo.setProto(a[0]);
            portInfo.setLocalAddress(a[1]);
            portInfo.setForeignAddress(a[2]);
            return portInfo;
        }).collect(Collectors.toList());
        return portInfos;
    }

    public static List<PortInfo> getPortInfo2() {
        List<InternetProtocolStats.IPConnection> cons = OshiCollectUtils.OS.getInternetProtocolStats().getConnections();
        return cons.stream().
                filter(con -> con.getType().contains("udp") ||
                        (con.getType().contains("tcp") && con.getState() == InternetProtocolStats.TcpState.LISTEN)).
                map(con -> {
                    PortInfo portInfo = new PortInfo();
                    portInfo.setProto(con.getType());
                    portInfo.setLocalAddress(bytesToIp(con.getLocalAddress(), con.getLocalPort()));
                    portInfo.setForeignAddress(bytesToIp(con.getForeignAddress(), con.getForeignPort()));
                    return portInfo;
                }).collect(Collectors.toList());
    }


    static String bytesToIp(byte[] src, int port) {
        String pstr = port == 0 ? "*" : String.valueOf(port);
        if (src.length == 4) {
            return bytes4ToIp(src, pstr);
        } else if (src.length == 16) {
            return bytes6ToIp(src, pstr);
        } else {
            return "*:" + pstr;
        }
    }

    static String bytes4ToIp(byte[] src, String port) {
        return (src[0] & 0xff) + "." + (src[1] & 0xff) + "." + (src[2] & 0xff) + "." + (src[3] & 0xff) + ":" + port;
    }

    static String bytes6ToIp(byte[] src, String port) {
        StringBuilder sb = new StringBuilder(46);
        try {
            sb.append("[");
            for (int i = 0; i < 8; i++) {
                sb.append(Integer.toHexString(((src[i << 1] << 8) & 0xff00)
                        | (src[(i << 1) + 1] & 0xff)));
                if (i < 7) {
                    sb.append(":");
                }
            }
            sb.append("]:").append(port);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

}
